import unittest
from unittest.mock import patch, call
import pandas as pd
from CalcTools import CalcServe, Tasklist, started_queue, DateTools
from Entity import Task, StartedTask


pd.set_option("display.max_rows", None)
pd.set_option("display.max_columns", None)
pd.set_option("display.width", None)

class TestTasklist(unittest.TestCase):
    def setUp(self):
        self.tasklist = Tasklist()

    def test_add_task(self):
        task1 = Task(user_id=1, task_id=1, description="Task 1", category="Work", priority=1, start=1,
                     during=2)
        self.tasklist.add_task(task1)
        self.assertEqual(len(self.tasklist.get_list()), 1)

    def test_delete_task(self):
        task1 = Task(user_id=1, task_id=1, description="Task 1", category="Work", priority=1, start=1,
                     during=2)
        self.tasklist.add_task(task1)
        self.tasklist.delete_task(1)
        self.assertEqual(len(self.tasklist.get_list()), 0)

    def test_modify_task_description(self):
        task1 = Task(user_id=1, task_id=1, description="Task 1", category="Work", priority=1, start=1,
                     during=2)
        self.tasklist.add_task(task1)
        self.tasklist.modify_task(1, "description", "Updated Task 1")
        updated_task = self.tasklist.find_task(1)
        self.assertEqual(updated_task.description, "Updated Task 1")

    def test_modify_task_priority(self):
        task1 = Task(user_id=1, task_id=1, description="Task 1", category="Work", priority=1, start=1,
                     during=2)
        task2 = Task(user_id=1, task_id=2, description="Task 2", category="Personal", priority=1, start=1,
                     during=60)
        self.tasklist.add_task(task1)
        self.tasklist.add_task(task2)

        self.tasklist.modify_task(1, "priority", 3)
        sorted_tasks = self.tasklist.get_list()
        self.assertEqual(sorted_tasks[0].get_priority(), 1)
        self.assertEqual(sorted_tasks[1].get_priority(), 3)

    def test_pop_task(self):
        task1 = Task(user_id=1, task_id=1, description="Task 1", category="Work", priority=1, start=1,
                     during=2)
        self.tasklist.add_task(task1)
        popped_task = self.tasklist.pop_task(1)
        self.assertEqual(len(self.tasklist.get_list()), 0)
        self.assertEqual(popped_task.task_id, 1)




class TestCalcServe(unittest.TestCase):
    def setUp(self):
        self.calserve = CalcServe()

        input_str = "20200303 020212"
        input_time = DateTools.timestamp_to_datetime(input_str)
        print(input_time)
        start_value = 1
        # 创建任务列表和已完成任务列表
        self.tasklist = Tasklist()
        # 添加任务到任务列表
        task1 = Task(user_id=1, task_id=1, description="Task 1", category="Work", priority=1, start=start_value,
                     during=2)
        task2 = Task(user_id=1, task_id=2, description="Task 2", category="Personal", priority=1, start=start_value,
                     during=60)
        task3 = Task(user_id=1, task_id=3, description="Task 3", category="Dajiao", priority=1, start=start_value,
                     during=40)
        task4 = Task(user_id=1, task_id=4, description="Task 4", category="valorant", priority=1, start=start_value,
                     during=50)

        self.tasklist.add_task(task1)
        self.tasklist.add_task(task2)
        self.tasklist.add_task(task3)
        self.tasklist.add_task(task4)
        self.tasklist.sorted_task()

        # 保存开始后的任务
        start_time_str1 = "2023-05-01 09:06:00"
        end_time_str1 = "2023-05-01 09:08:00"
        end_time_str2 = "2023-06-02 09:08:00"
        end_time_str3 = "2023-05-01 15:08:00"
        end_time_str4 = "2023-05-01 18:08:00"
        finished_task1 = StartedTask(start_time_str1, end_time_str1,
                                     task1.user_id, task1.task_id, task1.description,
                                     task1.category, task1.priority, task1.during)
        finished_task2 = StartedTask(start_time_str1, end_time_str2,
                                     task2.user_id, task2.task_id, task2.description,
                                     task2.category, task2.priority, task2.during)
        finished_task3 = StartedTask(start_time_str1, end_time_str3,
                                     task3.user_id, task3.task_id, task3.description,
                                     task3.category, task3.priority, task3.during)
        finished_task4 = StartedTask(start_time_str1, end_time_str4,
                                     task4.user_id, task4.task_id, task4.description,
                                     task4.category, task4.priority, task4.during)

        started_queue.append_task(finished_task1)
        started_queue.append_task(finished_task2)
        started_queue.append_task(finished_task3)
        started_queue.append_task(finished_task4)


    def test_create_everyday_df(self):
        result = CalcServe.create_everyday_df("table_name")
        # Check if the DataFrame is not empty before accessing elements
        self.assertFalse(result.empty, "Result DataFrame is empty")

        # Check other assertions only if the DataFrame is not empty
        self.assertEqual(result.iloc[0]['user_id'], 1)
        self.assertEqual(result.iloc[0]['task_id'], 1)
        self.assertEqual(result.iloc[0]['description'], "Task 1")
        self.assertEqual(result.iloc[0]['category'], "Work")
        self.assertEqual(result.iloc[0]['priority'], 1)
        self.assertEqual(result.iloc[0]['start'], 1)
        self.assertEqual(result.iloc[0]['during'], 2)
        self.assertEqual(result.iloc[0]['start_time_str'], "2023-05-01 09:06:00")
        self.assertEqual(result.iloc[0]['end_time_str'], "2023-05-01 09:08:00")
        self.assertEqual(result.iloc[0]['real_time'], 2)
        self.assertEqual(result.iloc[0]['finish'], True)

        self.assertEqual(result.iloc[1]['user_id'], 1)
        self.assertEqual(result.iloc[1]['task_id'], 2)
        self.assertEqual(result.iloc[1]['description'], "Task 2")
        self.assertEqual(result.iloc[1]['category'], "Personal")
        self.assertEqual(result.iloc[1]['priority'], 1)
        self.assertEqual(result.iloc[1]['start'], 1)
        self.assertEqual(result.iloc[1]['during'], 60)
        self.assertEqual(result.iloc[1]['start_time_str'], "2023-05-01 09:06:00")
        self.assertEqual(result.iloc[1]['end_time_str'], "2023-06-02 09:08:00")
        self.assertEqual(result.iloc[1]['real_time'], 46082)
        self.assertEqual(result.iloc[1]['finish'], False)

        self.assertEqual(result.iloc[2]['user_id'], 1)
        self.assertEqual(result.iloc[2]['task_id'], 3)
        self.assertEqual(result.iloc[2]['description'], "Task 3")
        self.assertEqual(result.iloc[2]['category'], "Dajiao")
        self.assertEqual(result.iloc[2]['priority'], 1)
        self.assertEqual(result.iloc[2]['start'], 1)
        self.assertEqual(result.iloc[2]['during'], 40)
        self.assertEqual(result.iloc[2]['start_time_str'], "2023-05-01 09:06:00")
        self.assertEqual(result.iloc[2]['end_time_str'], "2023-05-01 15:08:00")
        self.assertEqual(result.iloc[2]['real_time'], 362)
        self.assertEqual(result.iloc[2]['finish'], False)

        self.assertEqual(result.iloc[3]['user_id'], 1)
        self.assertEqual(result.iloc[3]['task_id'], 4)
        self.assertEqual(result.iloc[3]['description'], "Task 4")
        self.assertEqual(result.iloc[3]['category'], "valorant")
        self.assertEqual(result.iloc[3]['priority'], 1)
        self.assertEqual(result.iloc[3]['start'], 1)
        self.assertEqual(result.iloc[3]['during'], 50)
        self.assertEqual(result.iloc[3]['start_time_str'], "2023-05-01 09:06:00")
        self.assertEqual(result.iloc[3]['end_time_str'], "2023-05-01 18:08:00")
        self.assertEqual(result.iloc[3]['real_time'], 542)
        self.assertEqual(result.iloc[3]['finish'], False)

    @patch('pandas.DataFrame.to_sql', autospec=True)
    @patch('sqlite3.connect', autospec=True)
    def test_df_push_sql(self, mock_connect, mock_to_sql):
        db_file_name = 'db_file'
        table_name = 'table_name'
        test_dataframe = pd.DataFrame({
            'user_id': [1],
            'task_id': [1],
            'description': ["Task 1"],
            'category': ["Work"],
            'priority': [1],
            'start': [1],
            'during': [2],
            'start_time_str': ["2023-05-01 09:06:00"],
            'end_time_str': ["2023-05-01 09:08:00"],
            'real_time': [2],
            'finish': [True]
        })
        print(test_dataframe)

        mock_connection = mock_connect.return_value
        mock_cursor = mock_connection.cursor.return_value

        self.calserve.df_push_sql(test_dataframe, db_file_name, table_name)

        mock_connect.assert_called_once()
        mock_connect.return_value.cursor.assert_called_once()
        mock_cursor.execute.assert_has_calls([
            call(f"SELECT * FROM {table_name}"),
            call(f"DELETE FROM {table_name}")
        ], any_order=True)

    def test_get_df(self):
        result = self.calserve.get_df("2023-05-01 09:06:00", "day", 'db_file', 'table_name')
        print(result)

        self.assertIsInstance(result, pd.DataFrame)

        self.assertIsInstance(result, pd.DataFrame)
        self.assertEqual(result.iloc[0]['user_id'], 1)
        self.assertEqual(result.iloc[0]['task_id'], 1)
        self.assertEqual(result.iloc[0]['description'], "Task 1")
        self.assertEqual(result.iloc[0]['category'], "Work")
        self.assertEqual(result.iloc[0]['priority'], 1)
        self.assertEqual(result.iloc[0]['start'], 1)
        self.assertEqual(result.iloc[0]['during'], 2)
        self.assertEqual(result.iloc[0]['start_time_str'], "2023-05-01 09:06:00")
        self.assertEqual(result.iloc[0]['end_time_str'], "2023-05-01 09:08:00")
        self.assertEqual(result.iloc[0]['real_time'], 2)
        self.assertEqual(result.iloc[0]['finish'], True)

    def test_df_cal_focus_hour(self):
        result = self.calserve.df_cal_focus_hour("2023-05-01 09:06:00", "day", "db_file", "table_name")
        self.assertEqual(result, 15.1)
    def test_df_cal_num_finished_task(self):
        with patch.object(CalcServe, 'get_df', return_value=self.get_mock_dataframe()):
            result = CalcServe.df_cal_num_finished_task("2023-05-01 09:06:00", "day", "db_file", "table_name")

        self.assertEqual(result, 1)

    def test_df_cal_percentage(self):
        with patch.object(CalcServe, 'get_df', return_value=self.get_mock_dataframe()):
            result = CalcServe.df_cal_percentage("2023-05-01 09:06:00", "day", "db_file", "table_name")

        self.assertEqual(result, {'Work': 0.004256405890865753, 'Personal': 98.0718481314378, 'Dajiao': 0.7704094662467013, 'valorant': 1.1534859964246191})

    def get_mock_dataframe(self):
        return pd.DataFrame({
            'user_id': [1, 1, 1, 1],
            'task_id': [1, 2, 3, 4],
            'description': ["Task 1", "Task 2", "Task 3", "Task 4"],
            'category': ["Work", "Personal", "Dajiao", "valorant"],
            'priority': [1, 1, 1, 1],
            'start': [1, 1, 1, 1],
            'during': [2, 60, 40, 50],
            'start_time_str': ["2023-05-01 09:06:00"] * 4,
            'end_time_str': ["2023-05-01 09:08:00", "2023-06-02 09:08:00", "2023-05-01 15:08:00", "2023-05-01 18:08:00"],
            'real_time': [2, 46082, 362, 542],
            'finish': [True, False, False, False]
        })
class TestDateTools(unittest.TestCase):

    def test_timestamp_to_datetime(self):
        result = DateTools.timestamp_to_datetime("20200303 020212")
        expected_result = "2020-03-03 02:02:12"
        self.assertEqual(result, expected_result)

    def test_cal_first_end_time_day(self):
        date_time_str = "2023-05-01 09:06:00"
        freq = 'day'
        start_time, end_time = DateTools.cal_first_end_time(date_time_str, freq)

        expected_start_time = "2023-05-01 00:00:00"
        expected_end_time = "2023-05-01 23:59:59"

        self.assertEqual(start_time, expected_start_time)
        self.assertEqual(end_time, expected_end_time)

    def test_cal_first_end_time_week(self):
        date_time_str = "2023-05-01 09:06:00"
        freq = 'week'
        start_time, end_time = DateTools.cal_first_end_time(date_time_str, freq)

        expected_start_time = "2023-05-01 00:00:00"
        expected_end_time = "2023-05-07 23:59:59"

        self.assertEqual(start_time, expected_start_time)
        self.assertEqual(end_time, expected_end_time)

    def test_cal_first_end_time_month(self):
        date_time_str = "2023-05-01 09:06:00"
        freq = 'month'

        start_time, end_time = DateTools.cal_first_end_time(date_time_str, freq)

        expected_start_time = "2023-05-01 00:00:00"
        expected_end_time = "2023-05-31 23:59:59"

        self.assertEqual(start_time, expected_start_time)
        self.assertEqual(end_time, expected_end_time)

if __name__ == '__main__':
    unittest.main()


